Coverage Report

Created: 2024-12-26 12:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\compiler\structure.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::error::Error;
30
use crate::compiler::r#enum::Enum;
31
use crate::compiler::util::objects::name_index;
32
use crate::compiler::util::try2;
33
use crate::compiler::util::types::Name;
34
use crate::compiler::Protocol;
35
use crate::model::protocol::{Description, Endianness};
36
use crate::model::structure::{SimpleType, StructFieldRaw, StructFieldView};
37
use bp3d_debug::trace;
38
use std::cell::Cell;
39
use std::fmt::{Display, Formatter};
40
use std::rc::Rc;
41
42
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
43
pub enum FixedFieldType {
44
    Int8,
45
    Int16,
46
    Int32,
47
    Int64,
48
    UInt8,
49
    UInt16,
50
    UInt32,
51
    UInt64,
52
    Float32,
53
    Float64,
54
    Bool,
55
}
56
57
impl Display for FixedFieldType {
58
711
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59
711
        match self {
60
0
            FixedFieldType::Int8 => f.write_str("Int8"),
61
0
            FixedFieldType::Int16 => f.write_str("Int16"),
62
0
            FixedFieldType::Int32 => f.write_str("Int32"),
63
0
            FixedFieldType::Int64 => f.write_str("Int64"),
64
343
            FixedFieldType::UInt8 => f.write_str("UInt8"),
65
77
            FixedFieldType::UInt16 => f.write_str("UInt16"),
66
171
            FixedFieldType::UInt32 => f.write_str("UInt32"),
67
108
            FixedFieldType::UInt64 => f.write_str("UInt64"),
68
12
            FixedFieldType::Float32 => f.write_str("Float32"),
69
0
            FixedFieldType::Float64 => f.write_str("Float64"),
70
0
            FixedFieldType::Bool => f.write_str("Bool"),
71
        }
72
711
    }
73
}
74
75
242
fn map_numeric(
76
242
    ty: SimpleType,
77
242
    signed: FixedFieldType,
78
242
    unsigned: FixedFieldType,
79
242
    float: FixedFieldType,
80
242
) -> Option<FixedFieldType> {
81
242
    match ty {
82
28
        SimpleType::Signed => Some(signed),
83
210
        SimpleType::Unsigned => Some(unsigned),
84
4
        SimpleType::Float => Some(float),
85
0
        _ => None,
86
    }
87
242
}
88
89
impl FixedFieldType {
90
200
    pub fn get_byte_size(&self) -> usize {
91
200
        match self {
92
0
            FixedFieldType::Int8 => 1,
93
0
            FixedFieldType::Int16 => 2,
94
0
            FixedFieldType::Int32 => 4,
95
0
            FixedFieldType::Int64 => 8,
96
92
            FixedFieldType::UInt8 => 1,
97
24
            FixedFieldType::UInt16 => 2,
98
48
            FixedFieldType::UInt32 => 4,
99
36
            FixedFieldType::UInt64 => 8,
100
0
            FixedFieldType::Float32 => 4,
101
0
            FixedFieldType::Float64 => 8,
102
0
            FixedFieldType::Bool => 1,
103
        }
104
200
    }
105
106
6
    pub fn from_min_max_value(min_value: isize, max_value: isize) -> Result<Self, Error> {
107
6
        match min_value < 0 {
108
            true => {
109
2
                let bit_size = if max_value > i32::MAX as isize || min_value < i32::MIN as isize {
  Branch (109:35): [True: 0, False: 2]
  Branch (109:68): [True: 0, False: 2]
  Branch (109:35): [Folded - Ignored]
  Branch (109:68): [Folded - Ignored]
110
0
                    64
111
2
                } else if max_value > i16::MAX as isize || min_value < i16::MIN as isize {
  Branch (111:27): [True: 0, False: 2]
  Branch (111:60): [True: 0, False: 2]
  Branch (111:27): [Folded - Ignored]
  Branch (111:60): [Folded - Ignored]
112
0
                    32
113
2
                } else if max_value > i8::MAX as isize || min_value < i8::MIN as isize {
  Branch (113:27): [True: 0, False: 2]
  Branch (113:59): [True: 0, False: 2]
  Branch (113:27): [Folded - Ignored]
  Branch (113:59): [Folded - Ignored]
114
0
                    16
115
                } else {
116
2
                    8
117
                };
118
2
                Self::from_model(StructFieldRaw::Signed { bits: bit_size })
119
            }
120
            false => {
121
4
                let bit_size = if max_value > u32::MAX as isize {
  Branch (121:35): [True: 0, False: 4]
  Branch (121:35): [Folded - Ignored]
122
0
                    64
123
4
                } else if max_value > u16::MAX as isize {
  Branch (123:27): [True: 0, False: 4]
  Branch (123:27): [Folded - Ignored]
124
0
                    32
125
4
                } else if max_value > u8::MAX as isize {
  Branch (125:27): [True: 0, False: 4]
  Branch (125:27): [Folded - Ignored]
126
0
                    16
127
                } else {
128
4
                    8
129
                };
130
4
                Self::from_model(StructFieldRaw::Unsigned { bits: bit_size })
131
            }
132
        }
133
6
    }
134
135
32
    pub fn from_max_value(max_value: usize) -> Result<Self, Error> {
136
32
        let bit_size = if max_value > u32::MAX as usize {
  Branch (136:27): [True: 0, False: 32]
  Branch (136:27): [Folded - Ignored]
137
0
            64
138
32
        } else if max_value > u16::MAX as usize {
  Branch (138:19): [True: 4, False: 28]
  Branch (138:19): [Folded - Ignored]
139
4
            32
140
28
        } else if max_value > u8::MAX as usize {
  Branch (140:19): [True: 2, False: 26]
  Branch (140:19): [Folded - Ignored]
141
2
            16
142
        } else {
143
26
            8
144
        };
145
32
        Self::from_model(StructFieldRaw::Unsigned { bits: bit_size })
146
32
    }
147
148
265
    pub fn from_model(ty1: StructFieldRaw) -> Result<Self, Error> {
149
265
        let motherfuckingrust = ty1.clone();
150
265
        let ty = ty1.get_simple_type();
151
265
        let bit_size = ty1.get_bit_size();
152
265
        if ty == SimpleType::Boolean {
  Branch (152:12): [True: 12, False: 253]
  Branch (152:12): [Folded - Ignored]
153
12
            Ok(Self::Bool)
154
253
        } else if ty == SimpleType::Float && 
bit_size == 3214
{
  Branch (154:19): [True: 14, False: 239]
  Branch (154:46): [True: 6, False: 8]
  Branch (154:19): [Folded - Ignored]
  Branch (154:46): [Folded - Ignored]
155
6
            Ok(Self::Float32)
156
247
        } else if ty == SimpleType::Float && 
bit_size == 648
{
  Branch (156:19): [True: 8, False: 239]
  Branch (156:46): [True: 4, False: 4]
  Branch (156:19): [Folded - Ignored]
  Branch (156:46): [Folded - Ignored]
157
4
            Ok(Self::Float64)
158
243
        } else if bit_size > 32 && 
bit_size <= 6430
{
  Branch (158:19): [True: 30, False: 213]
  Branch (158:36): [True: 30, False: 0]
  Branch (158:19): [Folded - Ignored]
  Branch (158:36): [Folded - Ignored]
159
30
            map_numeric(ty, Self::Int64, Self::UInt64, Self::Float64).ok_or(Error::UnsupportedType(motherfuckingrust))
160
213
        } else if bit_size > 16 && 
bit_size <= 3251
{
  Branch (160:19): [True: 51, False: 162]
  Branch (160:36): [True: 51, False: 0]
  Branch (160:19): [Folded - Ignored]
  Branch (160:36): [Folded - Ignored]
161
51
            map_numeric(ty, Self::Int32, Self::UInt32, Self::Float64).ok_or(Error::UnsupportedType(motherfuckingrust))
162
162
        } else if bit_size > 8 && 
bit_size <= 1624
{
  Branch (162:19): [True: 24, False: 138]
  Branch (162:35): [True: 24, False: 0]
  Branch (162:19): [Folded - Ignored]
  Branch (162:35): [Folded - Ignored]
163
24
            map_numeric(ty, Self::Int16, Self::UInt16, Self::Float32).ok_or(Error::UnsupportedType(motherfuckingrust))
164
138
        } else if bit_size > 0 && 
bit_size <= 8137
{
  Branch (164:19): [True: 137, False: 1]
  Branch (164:35): [True: 137, False: 0]
  Branch (164:19): [Folded - Ignored]
  Branch (164:35): [Folded - Ignored]
165
137
            map_numeric(ty, Self::Int8, Self::UInt8, Self::Float32).ok_or(Error::UnsupportedType(motherfuckingrust))
166
        } else {
167
1
            Err(Error::UnsupportedBitSize(bit_size))
168
        }
169
265
    }
170
}
171
172
#[derive(Clone, Debug)]
173
pub struct Location {
174
    pub byte_offset: usize,
175
    pub bit_offset: usize,
176
    pub byte_size: usize,
177
    pub bit_size: usize,
178
}
179
180
impl Display for Location {
181
708
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182
708
        write!(
183
708
            f,
184
708
            "bytes {}..{}, bits {}..{}",
185
708
            self.byte_offset,
186
708
            self.byte_offset + self.byte_size,
187
708
            self.bit_offset,
188
708
            self.bit_offset + self.bit_size
189
708
        )
190
708
    }
191
}
192
193
impl Location {
194
125
    fn from_model(bit_size: usize, bit_offset: usize) -> Self {
195
125
        let byte_offset = bit_offset / 8;
196
125
        Self {
197
125
            byte_offset,
198
125
            bit_offset: bit_offset - byte_offset * 8,
199
125
            bit_size,
200
125
            byte_size: if bit_size % 8 != 0 {
  Branch (200:27): [True: 32, False: 93]
  Branch (200:27): [Folded - Ignored]
201
32
                (bit_size / 8) + 1
202
            } else {
203
93
                bit_size / 8
204
            },
205
        }
206
125
    }
207
}
208
209
#[derive(Clone, Debug)]
210
pub enum FieldRaw {
211
    /// Apply a raw C-like cast (used for unsigned > signed and unsigned > float of same bit size).
212
    Transmute,
213
214
    /// Apply a unsigned > signed cast on a non T-aligned value,
215
    /// the maximum positive value is passed in.
216
    SignedCast(usize),
217
218
    /// Don't do anything special, just return the raw value.
219
    None,
220
}
221
222
impl FieldRaw {
223
15
    pub fn is_none(&self) -> bool {
224
15
        
matches!0
(self, Self::None)
225
15
    }
226
227
115
    fn from_model(ty: SimpleType, bit_size: usize) -> FieldRaw {
228
115
        if ty == SimpleType::Float && 
bit_size != 3214
&&
bit_size != 648
{
  Branch (228:12): [True: 14, False: 101]
  Branch (228:39): [True: 8, False: 6]
  Branch (228:57): [True: 4, False: 4]
  Branch (228:12): [Folded - Ignored]
  Branch (228:39): [Folded - Ignored]
  Branch (228:57): [Folded - Ignored]
229
4
            return FieldRaw::None;
230
111
        }
231
111
        if ty == SimpleType::Signed && 
bit_size != 826
&&
bit_size != 1622
&&
bit_size != 3218
&&
bit_size != 6412
{
  Branch (231:12): [True: 26, False: 85]
  Branch (231:40): [True: 22, False: 4]
  Branch (231:57): [True: 18, False: 4]
  Branch (231:75): [True: 12, False: 6]
  Branch (231:93): [True: 10, False: 2]
  Branch (231:12): [Folded - Ignored]
  Branch (231:40): [Folded - Ignored]
  Branch (231:57): [Folded - Ignored]
  Branch (231:75): [Folded - Ignored]
  Branch (231:93): [Folded - Ignored]
232
10
            let max_value = 1 << (bit_size - 1);
233
10
            FieldRaw::SignedCast(max_value - 1)
234
101
        } else if ty == SimpleType::Unsigned {
  Branch (234:19): [True: 63, False: 38]
  Branch (234:19): [Folded - Ignored]
235
63
            FieldRaw::None
236
        } else {
237
38
            FieldRaw::Transmute
238
        }
239
115
    }
240
}
241
242
#[derive(Clone, Debug)]
243
pub enum FieldView {
244
    /// Apply a float view based on an affine transformation function.
245
    Float { a: f64, b: f64, a_inv: f64, b_inv: f64 },
246
247
    /// Apply an enum view.
248
    Enum(Rc<Enum>),
249
250
    /// Don't do anything special, just return the raw value.
251
    None,
252
}
253
254
impl FieldView {
255
119
    fn from_model(
256
119
        proto: &Protocol,
257
119
        ty: SimpleType,
258
119
        bit_size: usize,
259
119
        value: Option<StructFieldView>,
260
119
    ) -> Result<Self, Error> {
261
13
        match value {
262
7
            Some(StructFieldView::Enum { name }) => {
263
7
                if ty != SimpleType::Unsigned && 
ty != SimpleType::Signed3
{
  Branch (263:20): [True: 3, False: 4]
  Branch (263:50): [True: 1, False: 2]
  Branch (263:20): [Folded - Ignored]
  Branch (263:50): [Folded - Ignored]
264
1
                    return Err(Error::UnsupportedViewType(ty));
265
6
                }
266
6
                let r = proto.enums.get(&name).ok_or(Error::UndefinedReference(name))
?0
;
267
6
                Ok(FieldView::Enum(r.clone()))
268
            }
269
3
            Some(StructFieldView::FloatRange { min, max }) => {
270
3
                if ty != SimpleType::Float {
  Branch (270:20): [True: 1, False: 2]
  Branch (270:20): [Folded - Ignored]
271
1
                    return Err(Error::UnsupportedViewType(ty));
272
2
                }
273
2
                let raw_max: usize = (1 << bit_size) - 1;
274
2
                let a = max / (raw_max as f64);
275
2
                let b = min;
276
2
                let a_inv = 1.0 / a;
277
2
                let b_inv = -b;
278
2
                Ok(FieldView::Float { a, b, a_inv, b_inv })
279
            }
280
3
            Some(StructFieldView::FloatMultiplier { multiplier }) => {
281
3
                if ty != SimpleType::Float {
  Branch (281:20): [True: 1, False: 2]
  Branch (281:20): [Folded - Ignored]
282
1
                    return Err(Error::UnsupportedViewType(ty));
283
2
                }
284
2
                let a = multiplier;
285
2
                let b = 0.0;
286
2
                let a_inv = 1.0 / a;
287
2
                let b_inv = 0.0;
288
2
                Ok(FieldView::Float { a, b, a_inv, b_inv })
289
            }
290
            None => {
291
106
                if ty == SimpleType::Float && 
bit_size != 3211
&&
bit_size != 645
{
  Branch (291:20): [True: 11, False: 95]
  Branch (291:47): [True: 5, False: 6]
  Branch (291:65): [True: 1, False: 4]
  Branch (291:20): [Folded - Ignored]
  Branch (291:47): [Folded - Ignored]
  Branch (291:65): [Folded - Ignored]
292
1
                    return Err(Error::UnsupportedViewType(ty));
293
105
                }
294
105
                Ok(FieldView::None)
295
            }
296
        }
297
119
    }
298
}
299
300
#[derive(Clone, Debug)]
301
pub struct FixedField {
302
    pub bits_type: FixedFieldType,
303
    pub raw_type: FixedFieldType,
304
    pub view_type: FixedFieldType,
305
    pub raw: FieldRaw,
306
    pub view: FieldView,
307
    pub endianness: Endianness,
308
}
309
310
impl Display for FixedField {
311
600
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
312
600
        write!(f, "{}, {} endian", self.bits_type, self.endianness)
313
600
    }
314
}
315
316
#[derive(Clone, Debug)]
317
pub struct FixedArrayField {
318
    pub ty: FixedFieldType,
319
    pub array_len: usize,
320
    pub endianness: Endianness,
321
    pub item_bit_size: usize,
322
}
323
324
impl Display for FixedArrayField {
325
36
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
326
36
        write!(f, "{}[{}], {} endian", self.ty, self.array_len, self.endianness)
327
36
    }
328
}
329
330
#[derive(Clone, Debug)]
331
pub enum FieldType {
332
    Fixed(FixedField),
333
    Array(FixedArrayField),
334
    Struct(Rc<Structure>),
335
}
336
337
impl Display for FieldType {
338
708
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
339
708
        match self {
340
600
            FieldType::Fixed(v) => v.fmt(f),
341
36
            FieldType::Array(v) => v.fmt(f),
342
72
            FieldType::Struct(v) => f.write_str(v.name()),
343
        }
344
708
    }
345
}
346
347
impl FieldType {
348
275
    pub fn as_fixed(&self) -> Option<&FixedField> {
349
275
        match self {
350
275
            FieldType::Fixed(v) => Some(v),
351
0
            _ => None,
352
        }
353
275
    }
354
}
355
356
#[derive(Clone, Debug)]
357
pub struct Field {
358
    pub name: String,
359
    pub loc: Location,
360
    pub description: Option<Description>,
361
    pub ty: FieldType,
362
}
363
364
impl Display for Field {
365
708
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
366
708
        write!(f, "{}: {} ({})", self.name, self.ty, self.loc)
367
708
    }
368
}
369
370
impl Field {
371
133
    fn from_model(
372
133
        proto: &Protocol,
373
133
        fields: &[Field],
374
133
        mut last_bit_offset: usize,
375
133
        value: crate::model::structure::StructField,
376
133
    ) -> Result<(Self, usize), Error> {
377
133
        if (value.raw.is_none() && 
value.item_type.is_none()13
) || (value.raw.is_some() &&
value.item_type.is_some()120
) {
  Branch (377:13): [True: 13, False: 120]
  Branch (377:36): [True: 0, False: 13]
  Branch (377:67): [True: 120, False: 13]
  Branch (377:90): [True: 0, False: 120]
  Branch (377:13): [Folded - Ignored]
  Branch (377:36): [Folded - Ignored]
  Branch (377:67): [Folded - Ignored]
  Branch (377:90): [Folded - Ignored]
378
0
            return Err(Error::BadFieldType);
379
133
        }
380
133
        let (
ty, bit_size125
) = if let Some(
info120
) = value.raw {
  Branch (380:37): [True: 120, False: 13]
  Branch (380:37): [Folded - Ignored]
381
120
            let array_len = value.array_len.unwrap_or(1);
382
120
            if array_len == 0 {
  Branch (382:16): [True: 1, False: 119]
  Branch (382:16): [Folded - Ignored]
383
1
                return Err(Error::ZeroArray);
384
119
            }
385
119
            let mut bit_size = info.get_bit_size();
386
119
            let 
view115
= FieldView::from_model(proto, info.get_simple_type(), bit_size, value.view)
?4
;
387
115
            let raw = FieldRaw::from_model(info.get_simple_type(), bit_size);
388
115
            bit_size *= array_len;
389
115
            let 
ty114
= FixedFieldType::from_model(info)
?1
;
390
114
            if array_len > 1 {
  Branch (390:16): [True: 7, False: 107]
  Branch (390:16): [Folded - Ignored]
391
7
                if (bit_size / array_len) % 8 != 0 {
  Branch (391:20): [True: 1, False: 6]
  Branch (391:20): [Folded - Ignored]
392
1
                    return Err(Error::UnalignedArrayCodec);
393
6
                }
394
6
                (
395
6
                    FieldType::Array(FixedArrayField {
396
6
                        endianness: proto.endianness,
397
6
                        array_len,
398
6
                        ty,
399
6
                        item_bit_size: bit_size / array_len,
400
6
                    }),
401
6
                    bit_size,
402
6
                )
403
            } else {
404
107
                let bits_type = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits: bit_size })
?0
;
405
107
                let raw_type = match (bit_size, ty) {
406
4
                    (32, FixedFieldType::Float32) => FixedFieldType::Float32,
407
4
                    (64, FixedFieldType::Float64) => FixedFieldType::Float64,
408
2
                    (_, FixedFieldType::Float32) => bits_type,
409
2
                    (_, FixedFieldType::Float64) => bits_type,
410
95
                    _ => ty,
411
                };
412
107
                (
413
107
                    FieldType::Fixed(FixedField {
414
107
                        endianness: proto.endianness,
415
107
                        bits_type,
416
107
                        raw_type,
417
107
                        view_type: ty,
418
107
                        view,
419
107
                        raw,
420
107
                    }),
421
107
                    bit_size,
422
107
                )
423
            }
424
        } else {
425
13
            let item_type = unsafe { value.item_type.unwrap_unchecked() };
426
13
            let 
r = try2!12
(proto.structs.get(&item_type) =>
Error::UndefinedReference(item_type)1
);
427
12
            trace!("Solved reference {} => {:?}", item_type, r);
428
12
            (FieldType::Struct(r.clone()), r.bit_size)
429
        };
430
125
        let loc = match value.offset {
431
            None => {
432
121
                let loc = Location::from_model(bit_size, last_bit_offset);
433
121
                last_bit_offset += bit_size;
434
121
                loc
435
            }
436
4
            Some(v) => match v.relative_to {
437
                None => {
438
2
                    let start_bits = v.bits.unwrap_or(0);
439
2
                    let end_bits = start_bits + bit_size;
440
2
                    if end_bits > last_bit_offset {
  Branch (440:24): [True: 0, False: 2]
  Branch (440:24): [Folded - Ignored]
441
0
                        last_bit_offset = end_bits;
442
2
                    }
443
2
                    Location::from_model(bit_size, start_bits)
444
                }
445
2
                Some(name) => {
446
12
                    let 
field2
=
fields.iter().find(2
|v| v.name == name
).ok_or(Error::UndefinedReference(name))2
?0
;
447
2
                    let start_bits = field.loc.bit_offset + v.bits.unwrap_or(0);
448
2
                    let end_bits = start_bits + bit_size;
449
2
                    if end_bits > last_bit_offset {
  Branch (449:24): [True: 0, False: 2]
  Branch (449:24): [Folded - Ignored]
450
0
                        last_bit_offset = end_bits;
451
2
                    }
452
2
                    Location::from_model(bit_size, start_bits)
453
                }
454
            },
455
        };
456
125
        Ok((
457
125
            Self {
458
125
                name: value.name,
459
125
                ty,
460
125
                loc,
461
125
                description: value.description,
462
125
            },
463
125
            last_bit_offset,
464
125
        ))
465
133
    }
466
}
467
468
#[derive(Clone, Debug)]
469
pub struct Structure {
470
    pub name: String,
471
    pub description: Option<Description>,
472
    pub fields: Vec<Field>,
473
    pub byte_size: usize,
474
    pub bit_size: usize,
475
    used_in_header: Cell<bool>,
476
}
477
478
impl Structure {
479
10
    pub fn set_used_in_header(&self) {
480
10
        self.used_in_header.set(true);
481
10
    }
482
483
120
    pub fn is_used_in_header(&self) -> bool {
484
120
        self.used_in_header.get()
485
120
    }
486
487
76
    pub fn from_model(proto: &Protocol, value: crate::model::structure::Structure) -> Result<Structure, Error> {
488
76
        let mut fields = Vec::with_capacity(value.fields.len());
489
76
        let mut last_bit_offset = 0;
490
201
        for 
field133
in value.fields {
491
133
            let (
field, new_offset125
) = Field::from_model(proto, &fields, last_bit_offset, field)
?8
;
492
125
            fields.push(field);
493
125
            last_bit_offset = new_offset;
494
        }
495
68
        let s = Structure {
496
68
            name: value.name,
497
68
            description: value.description,
498
68
            fields,
499
68
            bit_size: last_bit_offset,
500
68
            byte_size: if last_bit_offset % 8 != 0 {
  Branch (500:27): [True: 0, False: 68]
  Branch (500:27): [Folded - Ignored]
501
0
                (last_bit_offset / 8) + 1
502
            } else {
503
68
                last_bit_offset / 8
504
            },
505
68
            used_in_header: Cell::new(false),
506
68
        };
507
68
        if s.bit_size == 0 {
  Branch (507:12): [True: 1, False: 67]
  Branch (507:12): [Folded - Ignored]
508
1
            return Err(Error::ZeroStruct);
509
67
        }
510
67
        Ok(s)
511
76
    }
512
}
513
514
name_index!(Structure => name);